package nx.arbitrators;

import nx.graphics.*;
import nx.behaviors.*;
import javax.swing.*;
import nx.utils.*;
import java.awt.Color;

/**
 * A simple cooperative arbiter. All the outputs of the behaviors are multiplied
 * by its gain, and then sumed. Only the enabled behaviors will be taken into accomunt.
 * Priority of behaviors are not used in this kind of arbiter.
 *
 * @author Alejandro Pustowka, Jonathan Hernandez.
 */
public class CooperativeArbitrator extends Arbitrator{

    /**
     * Set it to true to see debugging messages on the console.
     * TODO: Eliminar esto y cambiar por un Logger.
     */
    private boolean isDebugging=false;

    /**
     * TODO: Esto deberia irse!!!
     * A simple window for watching each output of the behaviors and the resulting
     * vector.
     */
    private VectorFrame frame;

    /**
     * TODO: Esto deberia irse!!!
     * A simple window for enabling or disabling the arbiter.
     */
    private ControlFrame cframe;
    
    /**
     * TODO: Esto deberia irse!!!
     * Defines if the frame window should be shown or not.
     */
    private boolean showFrame = false;
    
    /**
     * Simple constructor for arbiter.
     * @param name Name of this arbiter.
     * @param behaviors Behavior stack.
     * @param showFrame enable or disable the Window print.
     */
    public CooperativeArbitrator(String name, boolean showFrame) {

        super(name);

        this.showFrame = showFrame;

        
        if(showFrame)
        {
            frame = new VectorFrame("Arbitro",VectorFrame.CARTESIAN_COORD,10,10);
            frame.setVisible(true);
            cframe = new ControlFrame(this);
            cframe.setVisible(true);
        }
         
    }


    
    /**
     * TODO: Esto deberia irse!!!
     * Use another VectorFrame for this arbiter.
     * @param frame The new VectorFrame.
     */
    public void setFrame(JFrame frame)
    {
        this.frame = (VectorFrame)frame;
    }

    /**
     * Output of this Arbitrator. Same function as in NxBehavior, because an arbiter
     * can also behave as a single behavior, and can be mixed in a new behavior
     * stack
     * @return Sum of all the outputs of the behaviors.
     */
    @Override
    public Vector2D value()
    {
        //FIXME: No deberia ser Vector2D!!!
        Vector2D [] values = new Vector2D[this.behaviors.size()];

        //output of the arbitrator
        Vector2D total = new Vector2D(0f,0f,0);

        //This is the sum of magnitudes of all vectors.
        float sumMag = 0;
        //this is the magnitude of the biggest vector
        float maxMag = 0;

        for(int i=0;i<this.behaviors.size();i++){

            //get i-th behavior
            NxBehavior b = (NxBehavior)behaviors.get(i);
            //check if behavior is enabled, then check for its value and scale it
            //according to gain.
            if(b.enabled = true)
                values[i]=((Vector2D)((b)).value()).scale(b.getGain());
            else
                values[i] = new Vector2D();


            float actualMag = (float)values[i].getMag();
            //sum magnitude of all vectors
            sumMag += actualMag;


            if(maxMag < actualMag)
                    maxMag = actualMag;

            if(isDebugging)
                System.out.println("VECTORADDITIONARBITRATOR:\nVector No. "+Integer.toString(i)+" Mag: "+Float.toString((float)values[i].getMag())+" theta: "+Double.toString(Math.toDegrees(values[i].getAngle())));

        
        }

                
        for(int i=0;i<values.length;i++){
            total=total.add(values[i]);
            
        }
        if(sumMag == 0  && maxMag == 0)
                maxMag = sumMag = 1;
        total = total.scale(maxMag/sumMag);

        Vector2D[] copyVal = new Vector2D[values.length+1];

        String[] names = new String[values.length+1];
        if(showFrame)
        {
            frame.resetDynElements();

            for(int j=0;j<values.length;j++)
            {
                NxBehavior b = (NxBehavior)behaviors.get(j);
                Color c = Color.GRAY;
                switch(j)
                {
                    case 0:
                    case 4:
                    case 8:
                        c = Color.BLUE;
                    break;
                    case 1:
                    case 5:
                    case 9:
                        c = Color.GREEN;
                    break;
                    case 2:
                    case 6:
                    case 10:
                        c = Color.ORANGE;
                    break;
                    case 3:
                    case 7:
                    case 11:
                        c = Color.DARK_GRAY;
                    break;

                }
                frame.addDynElement(b.getName(), frame.VECTOR_ELEMENT,0,(float)values[j].getX(),(float)values[j].getY(),c);
                names[j] = b.getName();
            }
            frame.addDynElement("TOTAL", frame.VECTOR_ELEMENT,0,(float)total.getX(),(float)total.getY(),Color.RED);

            names[values.length] = "TOTAL";

            frame.repaint();
        }


        if(isDebugging)
            System.out.println("VECTORADDITIONARBITRATOR:\nFinal Mag: "+Float.toString((float)total.getMag())+" theta: "+Double.toString(Math.toDegrees(total.getAngle())));

        if(enabled)
        {
            //total.print(total.MODE_MA);

            return total;
        }
        else
            return new Vector2D(0,0,Vector2D.MODE_XY);

        
    
    }

    /**
     * Change debug mode.
     * @param state true or false.
     */
    public void setDebugMode(boolean state)
    {
        this.isDebugging = state;
    
    }
}
